package com.jay.example.IndoorPositioningSystem;

/****
 * https://gitee.com/unw1900/Indoor_Positioning_System
 */
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.util.Objects;


/***
 * 已将 DeviceScanActivity.java 内的功能整合到 MainActivity.java中
 *
 * Activity for scanning and displaying available BLE devices.
 */
public class DeviceScanActivity extends AppCompatActivity {

    private TextView name;
    public StringBuffer beaconList = new StringBuffer();
    Beacon myBeacon;
    int lastBeacon = 0;
    private ScanSettings mScannerSetting;
    private Kalman kalman_1,kalman_2,kalman_3,kalman_4;
    private int[] rssitest = new int[5];

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button StartScan = (Button) findViewById(R.id.startScan);
        iBeacon();
        initBLE();
        intiKalmanFilter();
        getBlePermissionFromSys();
        StartScan.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
            @Override
            public void onClick(View v) {
                Log.d("Button", "Click Button!");
                mScannerSetting = new ScanSettings.Builder()
                        //退到后台时设置扫描模式为高频率
                        .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
                        .build();
                scanLeDevice(true);
            }
        });

    }

    private TextView Ble_ID;
    private TextView Ble_UUID;
    private TextView Ble_Rssi;

    private void iBeacon() {
        Ble_ID = (TextView) findViewById(R.id.tv_value7);
        Ble_ID.setMovementMethod(ScrollingMovementMethod.getInstance());
    //    Ble_UUID = findViewById(R.id.tv_value2);
//        Ble_Rssi = findViewById(R.id.tv_value7);
        myBeacon = new Beacon();
    }


    /**
     * Activity for scanning and displaying available BLE devices.
     */
    private BluetoothAdapter bluetoothAdapter;
    private BluetoothLeScanner sBluetoothLeScanner;
    private boolean mScanning;
    private Handler scanHandler = new Handler();

    // Stops scanning after 10 seconds when SCAN_PERIOD = 10000.
    private static final long SCAN_PERIOD = 1000000;

    /**
     * 开启、关闭对BLE设备的扫描
     * @param enable true or false
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void scanLeDevice(final boolean enable) {
        if (enable) {
            // Stops scanning after a pre-defined scan period.
            scanHandler.postDelayed(new Runnable() {
                @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
                @Override
                public void run() {
                    mScanning = false;
//                    mScanning = !mScanning;
                    sBluetoothLeScanner.stopScan(myScanCallback);
                    Log.d("scanLeDevice", "---------Stop Scan-------");
                    Ble_Rssi.setText("已停止扫描");
                }
            }, SCAN_PERIOD);

            mScanning = true;
            sBluetoothLeScanner.startScan(null,mScannerSetting,myScanCallback);
            Log.d("scanLeDevice", "----------Start Scan--------");
            Ble_Rssi.setText("正在扫描...");
        } else {
            mScanning = false;
            Ble_Rssi.setText("已停止扫描");
            sBluetoothLeScanner.stopScan(myScanCallback);
        }
    }

    /**
     * 初始化Android设备的蓝牙
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public void initBLE() {

        final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        if (bluetoothManager != null) {
            bluetoothAdapter = bluetoothManager.getAdapter();
        }else { Log.d("DeviceScanActivity"," bluetoothManager.getAdapter() is null !!");}
        if (!bluetoothAdapter.isEnabled()) {//是否已开启蓝牙
            bluetoothAdapter.enable();
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//检测当前系统版本是否支持
            sBluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
            Log.d("initBLE", "\n\n-----------get Bluetooth LeScanner success!-----------\n\n");
        }else {
            Log.d("initBLE", "\n\n-----------error: get Bluetooth LeScanner failure!!   \n*return false of" +
                                        "Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP* -----------\n\n");
        }
    }

    private void intiKalmanFilter(){
        kalman_1 = new Kalman(9.0,100.0);//预测误差的方差,噪声误差的方差
        kalman_2 = new Kalman(9.0,100.0);
        kalman_3 = new Kalman(9.0,100.0);
        kalman_4 = new Kalman(9.0,100.0);

    }
    //    public ScanSettings myScanSeting = new ScanSettings(){
//
//    };
    /**
     * 源于 Android 蓝牙驱动包：android.bluetooth.le
     * 在发现 LE 蓝牙设备时自动回调,对扫描信息进行处理
     *
     * 重写：
     * 判断是否发现 Beacon 设备
     * 若发现新设备则存入历史记录，否则 更新已有设备信息
     * 打印已发现的 Beacon 设备信息
     */
    private ScanCallback myScanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, final ScanResult result) {
//            Log.d("myScanCallback", "\n------------发现 BLE 设备-----------------");
            runOnUiThread(new Runnable() {
                @RequiresApi(api = Build.VERSION_CODES.O)
                @Override
                public void run() {
//                    String newBeacon = Objects.requireNonNull(result.getScanRecord()).getDeviceName(); //得到设备名称
//                    int newRssi = Objects.requireNonNull(result.getRssi());
//                    boolean OE = Objects.requireNonNull(newBeacon).startsWith("OE");//是否是OE beacon
                    String newBeacon = Objects.requireNonNull(result.getScanRecord()).getDeviceName(); //得到设备名称
                    if (newBeacon != null) {
                        int newRssi = result.getRssi();
//                        boolean OE = false;//是否是OE beacon
//                        OE = newBeacon.startsWith("O");
//                        OE = newBeacon.endsWith("-1");
                        if (true) {
                            Ble_ID.append("----"+newBeacon+"-----\n");
//                            Ble_ID.append(" - " + newRssi+"\n");
                            Log.d("myScanCallback", "\n     发现蓝牙！:" + newBeacon+"\n");
                            int index = beaconList.indexOf(newBeacon);
                            if (index == -1) {
                                beaconList.append(newBeacon);
                                myBeacon.setName(lastBeacon, newBeacon);
                                myBeacon.setRssi(lastBeacon, newRssi);
                                lastBeacon += 1;

//                                Ble_ID.append("--"+result.getScanRecord().getDeviceName()+"--\n");
//                                Ble_UUID.setText("--"+result.getScanRecord().getDeviceName()+"--\n");
//                                Ble_Rssi.append("--"+result.getRssi()+"--\n");
                            } else {
                                index = (index/11);//分别
//                                rssitest[index] = newRssi;
                                int filterRssi = kalman_1.movingGaussianFilter(newRssi);
//                                int kalmanRssi = selectKalmanFilter(index, newRssi);
                                myBeacon.setRssi(index, filterRssi);
                            }
//                            Ble_ID.setText("");
//                            for (int i = 0; i < lastBeacon; i++) {
//                                Ble_ID.append("---------------------\n");
//                                Ble_ID.append("ID:" + i
//                                        + "  Name:" + myBeacon.getName(i)
//                                        + "  Rssi:" + myBeacon.getRssi(i)+"-- "+ rssitest[newRssi]
//                                        + "  ");
//                                distance(myBeacon.getRssi(i));
//                            }
                        }
                    }
                }
            });
        }
    };

    /**
     * 检测是否拥有权限
     */
    public void getBlePermissionFromSys() {
        if (Build.VERSION.SDK_INT >= 23) {
            int REQUEST_CODE_CONTACT = 102;
            String[] permissions = {Manifest.permission.ACCESS_COARSE_LOCATION};
            //验证是否许可权限
            for (String str : permissions) {
                if (this.checkSelfPermission(str) != PackageManager.PERMISSION_GRANTED) {
                    //申请权限
                    this.requestPermissions(permissions, REQUEST_CODE_CONTACT);
                    return;
                }
            }
        }//endregion
    }

    /**
     * 根据 RSSI 计算 Beacon 与 Android 设备的距离
     * @param rssi 接受到的 Beacon RSSI值
     * @return 距离，单位：米
     */
    private float distance(int rssi){  //RSSI = A - 10*n*lg(d)
        double Rssi = Math.abs(rssi);
        double power = (Rssi - 59) / (10.0 * 2);// n 原为3.3
        //93=10米    60=1米
        float distance = (float) Math.pow(10, power);
        String location= String.valueOf(distance);
        Ble_ID.append("\n     距离为："+ distance +"米\n\n");//返回6位有效数字

        return  distance;
    }

    private int selectKalmanFilter(int index, int newRssi){

        int kalmanRssi = 0;
        switch (index){
            case 0: kalmanRssi = (int) kalman_1.KalmanFilter(newRssi);break;
            case 1: kalmanRssi = (int) kalman_2.KalmanFilter(newRssi);break;
            case 2: kalmanRssi = (int) kalman_3.KalmanFilter(newRssi);break;
            case 3: kalmanRssi = (int) kalman_4.KalmanFilter(newRssi);break;
        }
        return kalmanRssi;
    }
}